package jsweb

import (
	"errors"
	"net/http"
	"os"
	"time"

	"gitee.com/haodreams/golib/autoroute/controller"
	"gitee.com/haodreams/golib/js/jstask"
	"gitee.com/haodreams/golib/js/jsutil"
	"gitee.com/haodreams/golib/logs"
	"github.com/dop251/goja"
)

var initJs func(vm *goja.Runtime) any

func SetInitJs(f jstask.CallBack) {
	initJs = f
}

// JsController 授权相关的操作
type JsController struct {
	controller.Controller
}

func (m *JsController) check(script string) (err error) {
	vm := goja.New()
	if initJs != nil {
		initJs(vm)
	}
	_, err = vm.RunString(script)
	if err != nil {
		logs.Warn(err)
		return
	}
	return err
}

// Tasks 同步任务
func (m *JsController) Tasks() {
	// typ := m.GetParam().GetTrimString("type")
	if m.IsPost() {
		boss := jstask.GetTasks()
		if boss == nil {
			m.Error("任务没有初始化")
			return
		}
		if boss.Job == nil {
			m.Error("没有有效的任务数据")
			return
		}
		tasks := boss.Job.GetTasks()
		m.Page(tasks, nil)
		// if typ == "async" {
		// 	tasks := boss.AsyncTask.GetTasks()
		// } else {
		// 	tasks := boss.SyncTask.GetTasks()
		// 	m.Page(tasks, nil)
		// }
		return
	}
	m.Display()
}

// Check 检查代码
func (m *JsController) Check() {
	param := m.GetParam()
	script := param.GetTrimString("js")
	err := m.check(script)
	if err != nil {
		m.Error(err.Error())
		return
	}
	m.Msg("OK")
}

// Test 测试代码
func (m *JsController) Test() {
	now := time.Now()
	param := m.GetParam()
	script := param.GetTrimString("js")
	vm := goja.New()
	var jsthis any
	if initJs != nil {
		jsthis = initJs(vm)
	}

	vm.Set("SetRunTimeout", func(timeout int64) {
		logs.Info("SetRunTimeout", timeout)
	})
	_, err := vm.RunString(script)
	if err != nil {
		logs.Warn(err)
		m.Error(err.Error())
		return
	}

	//自动检查是否有初始化函数
	setup, ok := goja.AssertFunction(vm.Get("setup"))
	if ok && setup != nil {
		_, err = setup(vm.ToValue(jsthis))
		if err != nil {
			logs.Warn(err.Error())
			return
		}
	}

	run, ok := goja.AssertFunction(vm.Get("run"))
	if !ok {
		err = errors.New("run  not a function")
		logs.Warn(err)
		return
	}
	runTime := time.Now()
	data, err := run(vm.ToValue(jsthis))
	if err != nil {
		logs.Warn(err)
		m.Error(err.Error())
		return
	}

	logs.Info("总耗时:", time.Since(now), "运行耗时:", time.Since(runTime))

	m.Msg(data.String())
}

// Test 测试代码
func (m *JsController) Download() {
	param := m.GetParam()
	script := param.GetTrimString("js")
	vm := goja.New()
	var jsthis any
	if initJs != nil {
		jsthis = initJs(vm)
	}
	vm.Set("SetRunTimeout", func(timeout int64) {
		logs.Info("SetRunTimeout", timeout)
	})

	_, err := vm.RunString(script)
	if err != nil {
		logs.Warn(err)
		m.Error(err.Error())
		return
	}
	setup, ok := goja.AssertFunction(vm.Get("setup"))
	if ok && setup != nil {
		_, err = setup(vm.ToValue(jsthis))
		if err != nil {
			logs.Warn(err.Error())
			return
		}
	}
	run, ok := goja.AssertFunction(vm.Get("run"))
	if !ok {
		err = errors.New("run  not a function")
		logs.Warn(err)
		return
	}
	rv, err := run(vm.ToValue(jsthis))
	if err != nil {
		logs.Warn(err)
		m.Error(err.Error())
		return
	}
	m.Writer.Header().Add("Content-Disposition", "attachment; filename=result.csv") //fmt.Sprintf("attachment; filename=%s", filename)对下载的文件重命名
	m.Writer.Header().Add("Content-Type", "application/octet-stream")
	m.Writer.WriteString(rv.String())
}

// Save 保存代码
func (m *JsController) Save() {
	fileName := m.GetParam().GetTrimString("name")
	if fileName == "" {
		m.Error("无效的文件名")
		return
	}
	script := m.GetParam().GetTrimString("js")
	err := m.check(script)
	if err != nil {
		m.Error(err.Error())
		return
	}
	err = os.WriteFile(jsutil.GetJsDir()+fileName, []byte(script), 0644)
	if err != nil {
		m.Error(err.Error())
		return
	}
	m.Msg("OK")
}

// File .
func (m *JsController) File() {
	path := jsutil.GetJsDir() + m.GetParam().GetString("path")
	data, err := os.ReadFile(path)
	if err != nil {
		m.Error(err.Error())
	} else {
		m.Msg(string(data))
	}
}

// Tree 标签
type Tree struct {
	ID       string  `json:"id"`
	Label    string  `json:"label"`
	Icon     string  `json:"icon"`
	Children []*Tree `json:"children"`
}

// List 列出所有文件
func (m *JsController) List() {
	path := jsutil.GetJsDir() + m.GetParam().GetString("path")
	fi, err := os.ReadDir(path)
	if err != nil {
		m.Error(err.Error())
		return
	}
	ifs := make([]*Tree, 0, len(fi))
	for _, f := range fi {
		if f.IsDir() {
			continue
		}
		inf := new(Tree)
		inf.Label = f.Name()
		inf.ID = f.Name()
		ifs = append(ifs, inf)
	}
	m.JSON(http.StatusOK, ifs)
}
